package br.unifor.escalonador.view;
import java.awt.EventQueue;

import javax.swing.JFrame;

import java.awt.Toolkit;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

import javax.swing.LayoutStyle.ComponentPlacement;

import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.Color;

import javax.swing.border.EtchedBorder;

import tst.Escalonador;
import tst.Processo;
import tst.algoritmo.FIFO;
import tst.algoritmo.FilasDePrioridadeHibrido;
import tst.algoritmo.RR;
import tst.algoritmo.SJF;
import tst.algoritmo.SRT;

import java.awt.Component;
import java.awt.Cursor;
import java.util.ArrayList;


public class TelaEscalonamento {
	JScrollPane panelprioridade1 = new JScrollPane();
	JScrollPane JpainelEscalonamento = new JScrollPane();
	private JFrame frmEscalonamento;
	//
	private ArrayList<Processo> listaProntos;
	private ArrayList<Processo> listaExecutando;
	private int quantidadeCores;
	private int quantidadeProcessos;
	private int novosProcessos=1;
	private int quantum;
	private int algoritmo;
	//
	private int geradorIdProcessos;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TelaEscalonamento window = new TelaEscalonamento();
					window.frmEscalonamento.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	public TelaEscalonamento() {
	}

	public TelaEscalonamento(int quantidadeProcessos, int quantidadeCores, int algoritmo, int quantum) {
		this.quantidadeProcessos = quantidadeProcessos;
		this.quantidadeCores = quantidadeCores;
		this.algoritmo = algoritmo;
		this.quantum = quantum;
		initialize();
	}

	private void initialize()  {
		frmEscalonamento = new JFrame();
		frmEscalonamento.getContentPane().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
		frmEscalonamento.getContentPane().setComponentOrientation(
				ComponentOrientation.LEFT_TO_RIGHT);
		frmEscalonamento.setTitle("Escalonamento");
		frmEscalonamento.setIconImage(Toolkit.getDefaultToolkit().getImage(
				"D:\\Projetos Unifor\\br.unifor.escalonador\\icon.jpg"));
		frmEscalonamento.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frmEscalonamento.setBounds(100, 100, 1212, 600);
		frmEscalonamento.setVisible(true);

		JButton btnAdicionarProcesso = new JButton("Adicionar Processo");
		btnAdicionarProcesso.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				adicionarProcessos();
			}
		});
		
//		JScrollPane JpainelEscalonamento = new JScrollPane();
		JpainelEscalonamento.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
		JpainelEscalonamento.setBorder(new EtchedBorder(EtchedBorder.LOWERED, Color.RED, null));
		
//		JScrollPane panelprioridade1 = new JScrollPane();
		panelprioridade1.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
		panelprioridade1.setAlignmentY(Component.TOP_ALIGNMENT);
		panelprioridade1.setAlignmentX(Component.LEFT_ALIGNMENT);
		panelprioridade1.setMaximumSize(new Dimension(40000, 40000));
		panelprioridade1.setBorder(new EtchedBorder(EtchedBorder.LOWERED, Color.BLACK, null));

		GroupLayout groupLayout = new GroupLayout(
				frmEscalonamento.getContentPane());
		groupLayout.setHorizontalGroup(
			groupLayout.createParallelGroup(Alignment.TRAILING)
				.addGroup(groupLayout.createSequentialGroup()
					.addGap(27)
					.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING, false)
						.addComponent(JpainelEscalonamento, Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 1126, GroupLayout.PREFERRED_SIZE)
						.addComponent(panelprioridade1, GroupLayout.PREFERRED_SIZE, 1126, GroupLayout.PREFERRED_SIZE))
					.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap(537, Short.MAX_VALUE)
					.addComponent(btnAdicionarProcesso)
					.addGap(503))
		);
		groupLayout.setVerticalGroup(
			groupLayout.createParallelGroup(Alignment.TRAILING)
				.addGroup(groupLayout.createSequentialGroup()
					.addGap(23)
					.addComponent(JpainelEscalonamento, GroupLayout.PREFERRED_SIZE, 187, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.UNRELATED)
					.addComponent(panelprioridade1, GroupLayout.DEFAULT_SIZE, 293, Short.MAX_VALUE)
					.addGap(18)
					.addComponent(btnAdicionarProcesso)
					.addGap(6))
		);
		frmEscalonamento.getContentPane().setLayout(groupLayout);
		selecionarAlgoritmo(algoritmo, quantum);
	}
	
	private void selecionarAlgoritmo(int algoritmo, int quantum) {
		Thread escalonar;
		Thread atualizar;
		// 0=FIFO, 1=Filas de prioridade hibrido, 2=RR, 3=SJF e 4=SRT
		switch (algoritmo) {
		case 0:
			final FIFO fifo = new FIFO(quantidadeProcessos, quantidadeCores);
			escalonar = new Thread(fifo);
			atualizar = new Thread( new Runnable() {
				@Override
				public void run() {
					while (true) {
						synchronized (fifo) {
							try {
								fifo.wait();
									atualizarNovosProcessos(fifo.getListaProntos(), fifo.getListaExecutando());
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}
			});
			escalonar.start();
			atualizar.start();	
			break;
		case 1:
			FilasDePrioridadeHibrido filasDePrioridadeHibrido = new FilasDePrioridadeHibrido();
			escalonar = new Thread(filasDePrioridadeHibrido);
			break;
		case 2:
			final RR roundRobin = new RR(quantidadeProcessos, quantidadeCores, quantum);
			escalonar = new Thread(roundRobin);
			atualizar = new Thread( new Runnable() {
				@Override
				public void run() {
					while (true) {
						synchronized (roundRobin) {
							try {
								roundRobin.wait();
									atualizarNovosProcessos(roundRobin.getListaProntos(), roundRobin.getListaExecutando());
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}
			});
			escalonar.start();
			atualizar.start();	
			break;
		case 3:
			final SJF sjf = new SJF(quantidadeProcessos, quantidadeCores);
			escalonar = new Thread(sjf);
			atualizar = new Thread( new Runnable() {
				@Override
				public void run() {
					while (true) {
						synchronized (sjf) {
							try {
								sjf.wait();
								if(novosProcessos != 0) {
								//	atualizarNovosProcessos();
								}
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
				}
			});
			escalonar.start();
			atualizar.start();	
			break;
		case 4:
			SRT srt = new SRT();
			break;
		}
	}
	public void atualizarNovosProcessos(ArrayList<Processo> listaProntos,ArrayList<Processo> listaExecutando) {
		for(int i = 0 ; i < listaProntos.size(); i++){
			JTextField tf = new JTextField(
				"P:"+listaProntos.get(i).getId()+	
				"TT:"+listaProntos.get(i).getTempoTotalExec()
					);
			tf.setEditable(false);
			tf.setColumns(6);
			panelprioridade1.add(tf);
		}
		
		for(int i = 0 ; i < listaExecutando.size(); i++){
			JTextField tf = new JTextField(
				"P:"+listaExecutando.get(i).getId()+	
				"TR:"+listaExecutando.get(i).getTempoRestanteExec()
					);
			tf.setEditable(false);
			tf.setColumns(6);
			JpainelEscalonamento.add(tf);
		}
		
		
	}
	public void adicionarProcessos() {
		geradorIdProcessos = quantidadeProcessos;
		quantidadeProcessos++;
		System.out.println("Adicionando o processo "+ geradorIdProcessos +" apos o inicio na lista de prontos");
		listaProntos.add( new Processo(geradorIdProcessos) );
	}

	
	
	
	
	
	
	
	
	
	
	
	/**
	 * @return the listaProntos
	 */
	public ArrayList<Processo> getListaProntos() {
		return listaProntos;
	}

	/**
	 * @param listaProntos the listaProntos to set
	 */
	public void setListaProntos(ArrayList<Processo> listaProntos) {
		this.listaProntos = listaProntos;
	}

	
	
	/**
	 * @return the listaExecutando
	 */
	public ArrayList<Processo> getListaExecutando() {
		return listaExecutando;
	}

	/**
	 * @param listaExecutando the listaExecutando to set
	 */
	public void setListaExecutando(ArrayList<Processo> listaExecutando) {
		this.listaExecutando = listaExecutando;
	}
}
